/*
  JETI_EX_SENSOR.cpp, Version 0.2
  Mars 2012, by Denis Artru
  alarm and jetibox display are based on work of Uwe Gartmann and Alexander Buschek
  written for Arduino Leonardo rx1/tx1
  written for Arduino MEGA using rx2/tx2
*/
#include <stdio.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <JETI_EX_SENSOR.h>

#if defined(__AVR_ATmega32U4__)
#define JETI_UART 1
#else
#define JETI_UART 2
#endif

#if JETI_UART == 1
   #if defined(__AVR_ATmega32U4__)
		#define JETI_RX_PIN 0
	#else
		#define JETI_RX_PIN 19
	#endif
#elif JETI_UART == 2
   #define JETI_RX_PIN 17
#endif	


#ifndef F_CPU
#define F_CPU 16000000
#endif
#if JETI_UART == 1
#define _UBRR1 (F_CPU/8/9600-1)  // when JETI_U1X is not set divider 16 instead of 8
#define JETI_UBRRx _UBRR1
#define JETI_U2Xx U2X1
#define JETI_UCSRxA UCSR1A
#define JETI_UCSRxB UCSR1B
#define JETI_UCSRxC UCSR1C
#define JETI_UBRRxH UBRR1H
#define JETI_UBRRxL UBRR1L
#define JETI_UMSELx0 UMSEL10
#define JETI_UPMx0 UPM10
#define JETI_USBSx USBS1
#define JETI_UCSZx0 UCSZ10
#define JETI_TXENx TXEN1
#define JETI_RXENx RXEN1
#define JETI_RXCIEx RXCIE1
#define JETI_UCSZx2 UCSZ12
#define JETI_UDRx UDR1
#define JETI_FEx FE1
#define JETI_DORx DOR1
#define JETI_UPEx UPE1
#define JETI_RXB8x RXB81
#define JETI_TXB8x TXB81
#define JETI_UDRIEx UDRIE1
#define JETI_USARTx_RX_vect USART1_RX_vect
#define JETI_USARTx_UDRE_vect USART1_UDRE_vect
#elif JETI_UART == 2
#define _UBRR2 (F_CPU/8/9600-1)  // when JETI_U2X is not set divider 16 instead of 8
#define JETI_UBRRx _UBRR2
#define JETI_U2Xx U2X2
#define JETI_UCSRxA UCSR2A
#define JETI_UCSRxB UCSR2B
#define JETI_UCSRxC UCSR2C
#define JETI_UBRRxH UBRR2H
#define JETI_UBRRxL UBRR2L
#define JETI_UMSELx0 UMSEL20
#define JETI_UPMx0 UPM20
#define JETI_USBSx USBS2
#define JETI_UCSZx0 UCSZ20
#define JETI_TXENx TXEN2
#define JETI_RXENx RXEN2
#define JETI_RXCIEx RXCIE2
#define JETI_UCSZx2 UCSZ22
#define JETI_UDRx UDR2
#define JETI_FEx FE2
#define JETI_DORx DOR2
#define JETI_UPEx UPE2
#define JETI_RXB8x RXB82
#define JETI_TXB8x TXB82
#define JETI_UDRIEx UDRIE2
#define JETI_USARTx_RX_vect USART2_RX_vect
#define JETI_USARTx_UDRE_vect USART2_UDRE_vect
#endif

#define LCDMaxPos 32
#define JETI_WAIT 3
#define JETI_REPEAT_ALARM 6
#define JB_MAX_FRAME_SIZE   0x46
#define JETI_TIME_BETWEEN_FRAME 20

volatile uint8_t JetiFrameState=0; /*0=wait; 1=create 2=ready to send */
static struct {
	volatile uint8_t buttons;
	volatile uint8_t dmyError;
	volatile uint8_t dmyBit9;
	volatile uint8_t dmyData;
	volatile uint8_t t0cntr;
	volatile uint8_t frameSize;
	volatile uint8_t sensorFrameName;
	char alarmEX;
	uint8_t nbValueEX;
	uint8_t trameCmpt;
	uint8_t valueToSend;
	uint8_t attente;
	uint8_t startExFrame;
	uint8_t alarmCmpt;
} jetiEx = {
	JB_key_none, /* buttons */
	0,
	0,
	0,
	JETI_TIME_BETWEEN_FRAME, /* t0cntr */
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	JETI_REPEAT_ALARM /* alarmCmpt */
};

static struct {
	int32_t* valueEX[0x10];
	const prog_char* nameEX[0x10];
	const prog_char* unitEX[0x10];
	volatile char lcd[LCDMaxPos];
	uint8_t precisionEX[0x10]; /* 0 int; 1,2,3 float; 4 date, 5 time, 6 GPS*/
	volatile uint8_t frame[JB_MAX_FRAME_SIZE];
	volatile uint8_t bit9[(JB_MAX_FRAME_SIZE/8)+1];
} jetiExBuffer ;

#ifdef openEx
#else
const static uint8_t JETI_codage[4] = {0x52,0x1C,0x6C,0x23};
#endif

#if defined(__AVR_ATmega32U4__)
/* 8-bit CRC polynomial  X^8 + X^2 + X + 1 */
#define POLY 0x07
static uint8_t jeti_update_crc (uint8_t crc, const uint8_t crc_seed)
{
    uint8_t crc_u;
    uint8_t i;
    crc_u = crc;
    crc_u ^= crc_seed;
    for (i=0; i<8; i++) {
        crc_u = ( crc_u & 0x80 ) ? POLY ^ ( crc_u << 1 ) : ( crc_u << 1 );
    }
    return crc_u;
}
#else
const byte jeti_crctable[256] PROGMEM = {
	0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
	0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
	0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
	0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
	0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
	0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
	0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
	0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
	0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
	0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
	0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
	0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
	0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
	0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
	0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
	0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
	0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
	0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
	0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
	0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
	0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
	0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
	0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
	0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
	0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
	0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
	0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
	0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
	0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
	0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
	0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
	0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
};
#endif


void JETI_Init(const prog_char* sensorName) {
   static int i_Loop=0;
   /* Init Serial Port */
   JETI_UCSRxA = (1<<JETI_U2Xx);  //JETI_U2Xx enabled
   JETI_UBRRxH=(JETI_UBRRx>>8);
   JETI_UBRRxL=JETI_UBRRx;
   JETI_UCSRxC=(0<<JETI_UMSELx0)|(3<<JETI_UPMx0)|(0<<JETI_USBSx)|(3<<JETI_UCSZx0); // 00=asynch, 11=Odd, 1 1Stop, 11 9 Bit , 0 default
   JETI_UCSRxB=(0<<JETI_TXENx)|(0<<JETI_RXENx)|(1<<JETI_RXCIEx)|(1<<JETI_UCSZx2);

   // config additional timer 0 interrupts
   OCR0A = 128;
   TIMSK0 |= _BV(OCIE0A);

	digitalWrite(JETI_RX_PIN, LOW);
	
	jetiExBuffer.nameEX[0]=sensorName;
	jetiExBuffer.unitEX[0]=PSTR(" ");
	jetiEx.nbValueEX=1;
}

uint8_t JETI_addData(const prog_char* name, const prog_char* unit) {
   // Prepare EX data
   jetiExBuffer.nameEX[jetiEx.nbValueEX]=name;
	jetiExBuffer.unitEX[jetiEx.nbValueEX]=unit;
	jetiExBuffer.valueEX[jetiEx.nbValueEX]=0;
	jetiExBuffer.precisionEX[jetiEx.nbValueEX]=0;
	jetiEx.nbValueEX++;
	jetiEx.attente=JETI_WAIT+5+jetiEx.nbValueEX*6;
	return(jetiEx.nbValueEX-1);
}

void JETI_setValue(uint8_t ident, int32_t* valuePtr, uint8_t precision) {
	jetiExBuffer.valueEX[ident]=valuePtr;
	jetiExBuffer.precisionEX[ident]=precision;
}
void JETI_setValueDate(uint8_t ident, uint8_t date[3]) {
	jetiExBuffer.valueEX[ident]=(int32_t*)date;
	jetiExBuffer.precisionEX[ident]=4;
}
void JETI_setValueTime(uint8_t ident, uint8_t time[3]) {
	jetiExBuffer.valueEX[ident]=(int32_t*)time;
	jetiExBuffer.precisionEX[ident]=5;
}
void JETI_setValueGPS(uint8_t ident, uint8_t coordinate[4]) {
	jetiExBuffer.valueEX[ident]=(int32_t*)coordinate;
	jetiExBuffer.precisionEX[ident]=6;
}
void JETI_unsetValue(uint8_t ident) {
	jetiExBuffer.valueEX[ident]=0;
	jetiExBuffer.precisionEX[ident]=0;
}

void JETI_alarm(char alarmLetter) {
	jetiEx.alarmEX=alarmLetter;
}

static void copyJetiLine(volatile char* JetiLine, const char* line) {
    uint8_t i;
    uint8_t length = strlen(line);
    for (i=0; i<(LCDMaxPos/2);i++) {
        if (i<length) {
            JetiLine[i] = line[i];
        } else {
            JetiLine[i] = ' ';
        }
    }
}
static void copyJetiLine_P(volatile char* JetiLine, const prog_char* line) {
	uint8_t i;
	uint8_t length = strlen_P(line);
	strncpy_P((char*)JetiLine,line,LCDMaxPos/2);
	for (i=length; i<(LCDMaxPos/2);i++) {
		JetiLine[i] = ' ';
	}
}

void JETI_JetiBox(const char* line1, const char* line2) {
    uint8_t i;
    uint8_t length;
    copyJetiLine(jetiExBuffer.lcd,line1);
    copyJetiLine(&(jetiExBuffer.lcd[LCDMaxPos/2]),line2);
}
void JETI_JetiBox_P(const prog_char* line1, const char* line2) {
	uint8_t i;
	uint8_t length;
	copyJetiLine_P(jetiExBuffer.lcd,line1);
	copyJetiLine(&(jetiExBuffer.lcd[LCDMaxPos/2]),line2);
}

#define JETI_SET_BIT9_FALSE jetiExBuffer.bit9[cmpt/8]&=~(1<<(cmpt%8));
bool JETI_createFrame() {
	uint8_t key;
	uint8_t crc8=0;
	uint8_t i_Loop;
	uint8_t identSend;
	int32_t value;
	uint8_t *valeur;
	if (JetiFrameState!=1) {
		return false;
	}
	memset((void*)jetiExBuffer.bit9,0xFF,(JB_MAX_FRAME_SIZE/8)+1);
	int cmpt=0;
	if (jetiEx.alarmEX) {
		jetiExBuffer.frame[0]=0x7E;
		jetiExBuffer.frame[1]=0x92;
		jetiExBuffer.frame[2]=0x23;
		jetiExBuffer.frame[3]=jetiEx.alarmEX;
#ifdef openEx
		jetiExBuffer.bit9[0]=0xFE;
#else
		jetiExBuffer.bit9[0]=0xF8;
#endif
		cmpt=4;
		if (jetiEx.alarmCmpt) {
			jetiEx.alarmCmpt--;
		} else {
			jetiEx.alarmEX=0;
			jetiEx.alarmCmpt=JETI_REPEAT_ALARM;
		}
	}
    if ((jetiEx.attente)>=JETI_WAIT&&(jetiEx.attente&0x0001)) {
        jetiExBuffer.frame[cmpt]=0x7E;
        JETI_SET_BIT9_FALSE
        cmpt++;
        jetiExBuffer.frame[cmpt]=0x9F;
#ifdef openEx
#else
		  JETI_SET_BIT9_FALSE
#endif
		  jetiExBuffer.frame[cmpt+1]=0x00;
        jetiExBuffer.frame[cmpt+2]=JETI_SENSOR_ID1;
        jetiExBuffer.frame[cmpt+3]=JETI_SENSOR_ID2;
        jetiExBuffer.frame[cmpt+4]=JETI_SENSOR_ID3;
        jetiExBuffer.frame[cmpt+5]=JETI_SENSOR_ID4;
#ifdef openEx
		 jetiExBuffer.frame[cmpt+6]=0;
#else
		 key=(uint8_t)random(0xFE)+1;
        jetiExBuffer.frame[cmpt+6]=key;
#endif
		 cmpt+=7;
        jetiEx.startExFrame = cmpt;
		for (i_Loop=0; i_Loop<jetiEx.nbValueEX; i_Loop++) {
			if (jetiExBuffer.valueEX[i_Loop]!=0) {
				jetiEx.trameCmpt++;
				jetiEx.trameCmpt%=32;
				break;
			}
		}
		if ((jetiEx.attente==JETI_WAIT)&&(jetiEx.trameCmpt!=0)&&(i_Loop<jetiEx.nbValueEX)) {
			jetiExBuffer.frame[jetiEx.startExFrame-6]=0x40;
			while (jetiExBuffer.valueEX[jetiEx.valueToSend]==0) {
				jetiEx.valueToSend++;
				if (jetiEx.valueToSend>=jetiEx.nbValueEX) {
					jetiEx.valueToSend=0;
				}
			}
			jetiEx.valueToSend=1+((jetiEx.valueToSend-1)/3)*3;
			for (i_Loop=0; i_Loop<3; i_Loop++) {
				identSend=i_Loop+jetiEx.valueToSend;
				if (identSend>=jetiEx.nbValueEX) {
					break;
				}
				if (jetiExBuffer.valueEX[identSend]==0) {
					continue;
				}
				// 5 for date/time 3 octets
				// 9 for GPS 4 octets
				jetiExBuffer.frame[cmpt]=identSend<<4;
				crc8=cmpt;
				cmpt++;
				if (jetiExBuffer.precisionEX[identSend]<4) {
                    value=*(jetiExBuffer.valueEX[identSend]);
                    jetiExBuffer.frame[cmpt]=(uint8_t)byte(value&0xFF);
                    if ((-31>value)||(value>31)) {
                        jetiExBuffer.frame[crc8]+=0x01;
                        cmpt++;
                        value=value>>8;
                        jetiExBuffer.frame[cmpt]=(uint8_t)byte(value&0xFF);
                    }
                    if ((-31>value)||(value>31)) {
                        jetiExBuffer.frame[crc8]+=0x03;
                        cmpt++;
                        value=value>>8;
                        jetiExBuffer.frame[cmpt]=(uint8_t)byte(value&0xFF);
                    }
                    // Only 6 digit can be print
//                    if ((-31>value)||(value>31)) {
//                        jetiExBuffer.frame[crc8]+=0x04;
//                        cmpt++;
//                        value=value>>8;
//                        jetiExBuffer.frame[cmpt]=(uint8_t)byte(value&0xFF);
//                    }
                    jetiExBuffer.frame[cmpt]=(jetiExBuffer.frame[cmpt]&0x9F)|((jetiExBuffer.precisionEX[identSend])<<5);
                    cmpt++;
				} else if (jetiExBuffer.precisionEX[identSend]<6) {
					jetiExBuffer.frame[crc8]|=0x05;
					valeur=((uint8_t*)jetiExBuffer.valueEX[identSend]);
					jetiExBuffer.frame[cmpt]=valeur[2];
					jetiExBuffer.frame[cmpt+1]=valeur[1];
					jetiExBuffer.frame[cmpt+2]=valeur[0];
					jetiExBuffer.frame[cmpt+2]&=0x1F;
					if (jetiExBuffer.precisionEX[identSend]==4) {
						jetiExBuffer.frame[cmpt+2]|=0x20;
					}
					cmpt+=3;
				} else if (jetiExBuffer.precisionEX[identSend]==6) {
					jetiExBuffer.frame[crc8]|=0x09;
					valeur=((uint8_t*)jetiExBuffer.valueEX[identSend]);
					jetiExBuffer.frame[cmpt]=valeur[3];
					jetiExBuffer.frame[cmpt+1]=valeur[2];
					jetiExBuffer.frame[cmpt+2]=valeur[1];
					cmpt+=3;
					jetiExBuffer.frame[cmpt]=0;
					switch (valeur[0]) {
						//case 'N':
						//	jetiExBuffer.frame[cmpt]=0x00;
						//	break;
						case 'S':
							jetiExBuffer.frame[cmpt]=0x40;
							break;
						case 'E':
							jetiExBuffer.frame[cmpt]=0x20;
							break;
						case 'W':
							jetiExBuffer.frame[cmpt]=0x60;
							break;
					}
					cmpt++;
				}
#ifdef openEx
#else
				if (i_Loop==0) {
					jetiExBuffer.frame[crc8+1]^=0x20;
				}
#endif
			}
			jetiEx.valueToSend+=3;
			if (jetiEx.valueToSend>=jetiEx.nbValueEX) {
				jetiEx.valueToSend=0;
			}

        } else {
            jetiExBuffer.frame[cmpt]=jetiEx.sensorFrameName;
            jetiExBuffer.frame[cmpt+1]=0;
			  value=strlen_P(jetiExBuffer.nameEX[jetiEx.sensorFrameName]);
#ifdef openEx
			  jetiExBuffer.frame[cmpt+1]|=(value<<3);
#else
            jetiExBuffer.frame[cmpt+1]|=((value-4)<<3);
            jetiExBuffer.frame[cmpt+1]|=((jetiExBuffer.frame[cmpt+1]&0x20)<<1);
#endif
			  i_Loop=strlen_P(jetiExBuffer.unitEX[jetiEx.sensorFrameName]);
            jetiExBuffer.frame[cmpt+1]|=(i_Loop&0x03);
            cmpt+=2;
			  strcpy_P((char *)&(jetiExBuffer.frame[cmpt]),jetiExBuffer.nameEX[jetiEx.sensorFrameName]);
			  cmpt+=value;
			  strcpy_P((char *)&(jetiExBuffer.frame[cmpt]),jetiExBuffer.unitEX[jetiEx.sensorFrameName]);
			  cmpt+=i_Loop;
			jetiEx.sensorFrameName++;
			jetiEx.sensorFrameName%=jetiEx.nbValueEX;
		}
		// Finish the EX frame; //
#ifdef openEx
#else
		// Crypt data
		jetiExBuffer.frame[jetiEx.startExFrame]=jetiExBuffer.frame[jetiEx.startExFrame] ^ key ^ 0x6D;
		for (i_Loop=(jetiEx.startExFrame+1);i_Loop<cmpt;i_Loop++) {
		   jetiExBuffer.frame[i_Loop]=jetiExBuffer.frame[i_Loop] ^ key ^ (JETI_codage[i_Loop%4] + ((i_Loop%2)?((i_Loop-8)&0xFC):0));
		   if (key & 0x02) {
		       jetiExBuffer.frame[i_Loop]^=0x3F;
		   }
		}
#endif
		// Set the length

		jetiExBuffer.frame[jetiEx.startExFrame-6]|=cmpt-2;
#ifdef openEx
#else
		if (!(jetiExBuffer.frame[jetiEx.startExFrame-6] & 0x02)) {jetiExBuffer.frame[jetiEx.startExFrame]^=0x3F;}
#endif
		 // Compute crc8 (last data);
		crc8=0;
		for (i_Loop=2; i_Loop<cmpt; i_Loop++) {
#if defined(__AVR_ATmega32U4__)
            crc8=jeti_update_crc(jetiExBuffer.frame[i_Loop],crc8);
#else
			crc8=pgm_read_byte(&(jeti_crctable[(crc8 ^ jetiExBuffer.frame[i_Loop])]));
#endif
		}
		jetiExBuffer.frame[cmpt]=crc8;
		cmpt++;
	}
#ifdef openEx
//	// Navigation within Expander menu
//	jetiExBuffer.frame[cmpt]=0x7E;
//	jetiExBuffer.frame[cmpt+1]=0x91;
//	jetiExBuffer.frame[cmpt+2]=0x31;
//	cmpt+=3;
#endif
    // Send the value to print on jetiBox 2*16 characters
    // only if there is space left on buffer. 
    if (cmpt<(JB_MAX_FRAME_SIZE-(LCDMaxPos+2))) {
        jetiExBuffer.frame[cmpt]=0xFE;
        JETI_SET_BIT9_FALSE
        cmpt++;
        memcpy ((void*)&(jetiExBuffer.frame[cmpt]), (const void*)jetiExBuffer.lcd, LCDMaxPos);
        cmpt+=LCDMaxPos;
        jetiExBuffer.frame[cmpt]=0xFF;
        JETI_SET_BIT9_FALSE
        cmpt++;
    }
    if (jetiEx.attente) {
        jetiEx.attente--;
    } else {
        jetiEx.attente=JETI_WAIT;
    }
    jetiEx.frameSize=cmpt;
    JetiFrameState=2;
    return true;
}

uint8_t JETI_readbuttons() {
	uint8_t currentButtons = jetiEx.buttons;
	jetiEx.buttons = JB_key_none;
	return currentButtons;
}

///////////////////////////////////
// Interupts

ISR(JETI_USARTx_RX_vect) {		//serial data available
	// catch response from Jetibox
	jetiEx.dmyError = JETI_UCSRxA;
	jetiEx.dmyBit9 = JETI_UCSRxB;
	jetiEx.dmyData = JETI_UDRx;
	if (!(jetiEx.dmyError & ((1<<JETI_FEx) | (1<<JETI_DORx) | (1<<JETI_UPEx)))) { // check for frame error, data overflow, parity error
		if ((jetiEx.dmyBit9 & (1<<JETI_RXB8x)) == 0) { //  check bit 9=0 for control data
			if ((jetiEx.dmyData & 0x0F) == 0) { // check for plausible button data: mask the 0x?0
				jetiEx.buttons = (jetiEx.dmyData>>4) xor 0x0F;
				jetiEx.t0cntr = JETI_TIME_BETWEEN_FRAME; // set JETI_TIME_BETWEEN_FRAMEms delay
			} 
		}
	}
}

volatile uint8_t JETI_sendpos;
ISR(JETI_USARTx_UDRE_vect) {	//transmit buffer empty
	if (JETI_sendpos==0) {
		JETI_UCSRxB&=~(1<<JETI_RXENx);
		digitalWrite(JETI_RX_PIN, LOW);
	}
	if (JETI_sendpos<jetiEx.frameSize) {
		if (jetiExBuffer.bit9[JETI_sendpos/8]&(1<<(JETI_sendpos%8))) {
			JETI_UCSRxB |= (1<<JETI_TXB8x); // set bit 9
		} else {
			JETI_UCSRxB &= ~(1<<JETI_TXB8x);  // clear bit 9
		}
		JETI_UDRx = jetiExBuffer.frame[JETI_sendpos];
		JETI_sendpos++;
	} else {
		JETI_UCSRxB &= ~(1<<JETI_UDRIEx);
		JETI_UCSRxB|=(1<<JETI_RXENx);
		digitalWrite(JETI_RX_PIN, HIGH);
		JETI_UCSRxB &= ~(1<<JETI_TXENx);
		jetiEx.t0cntr=JETI_TIME_BETWEEN_FRAME;
		// reset JETI_sendpos to 0
		JETI_sendpos = 0;
		JetiFrameState=0;
	}

}

ISR(TIMER0_COMPA_vect) { // Timer 0 CompA event
// This timer interrupt delays sending the next frame to the Jeti Box (in ms)
// The main function of timer0 belongs to millis() 
	switch (jetiEx.t0cntr) {
		case 0: 
			break;
		case 1:
			if (JetiFrameState==2) {
			   --jetiEx.t0cntr;
            JETI_UCSRxB |= (1<<JETI_TXENx);
			   JETI_UCSRxB |= (1<<JETI_UDRIEx); // enable send_buffer_empty interrupt to start transmission
			}
			break;
		case 5:
			if(JetiFrameState==0) {
				JetiFrameState=1;
			}
		default: 
			--jetiEx.t0cntr;
	}
}
